/************************************************************************
              ReadObj.cpp - Copyright Claudio Botta

This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110, USA

**************************************************************************/

// ReadObj extracts the basic features of the OBJ-format.
// The Obj-Format basically consists of Polygons
// This reader allows for testing converters converting from 'Polygons' to 
// different representations with 'real-worl' data.
//
// The format is sufficiently specified at http://en.wikipedia.org/wiki/Obj

#include "readObj.h"
using namespace geomagick;

Polygons Model;

using namespace std;
using namespace boost;
using namespace boost::iostreams;


string number = "0123456789-.e";
string number_group = "0123456789-.e/";
/*
string pop_slash(string& inStr)
{

	return "/"
}
*/ 

string pop_not_number(string& inStr)
{
	string::size_type from = inStr.find_first_not_of(number);
	if(from == string::npos) return "";
	inStr = inStr.substr(from);
	string::size_type to = inStr.find_first_of(number);
	if(to == string::npos || from == string::npos || to > inStr.size() || from > inStr.size()) to = inStr.size();
	//if(to > 0) to -= 1;
	string out =  inStr.substr(0,to);
	inStr = inStr.substr(to);
	return out;
}

string pop_number(string& inStr)
{
	string::size_type from = inStr.find_first_of(number);
	if(from == string::npos) return "";
	inStr = inStr.substr(from);
	string::size_type to = inStr.find_first_not_of(number);
	if(to == string::npos || from == string::npos || to > inStr.size() || from > inStr.size()) to = inStr.size();
	string out =  inStr.substr(0,to);
	inStr = inStr.substr(to);
	return out;
	
}

void addPolygon(string faceString)
{
	string nbr;
	string iNbr;
	nbr = pop_number(faceString);
	
	Polygon newPoly;
	std::vector<int> Vertices;
	std::vector<int> Normals;
	std::vector<int> TextureCoordinates;
	
	while(nbr.compare("") != 0)
	{
		newPoly.Vertices.push_back(atoi(nbr.c_str()) - 1);

		iNbr = pop_not_number(faceString);
		if(iNbr.find("/") !=  string::npos)
		{		
		nbr = pop_number(faceString);
		newPoly.Normals.push_back(atoi(nbr.c_str()) - 1);
		iNbr = pop_not_number(faceString);
		}
		if(iNbr.find("/") != string::npos)
		{
		nbr = pop_number(faceString);
		newPoly.TextureCoordinates.push_back(atoi(nbr.c_str()) - 1);
		} 
		nbr = pop_number(faceString);
	}
	
	Model.addPolygon(newPoly);
}

void addVertexCoordinates(string vertexCoordinates)
{
	string vertexCoordinateX = pop_number(vertexCoordinates);
	string vertexCoordinateY = pop_number(vertexCoordinates);
	string vertexCoordinateZ = pop_number(vertexCoordinates);
	Vector3d VertexCoordinates;
	VertexCoordinates.x = atof(vertexCoordinateX.c_str());
	VertexCoordinates.y = atof(vertexCoordinateY.c_str());
	VertexCoordinates.z = atof(vertexCoordinateZ.c_str());
	Model.addVertexCoordinates(VertexCoordinates);
	//cout << "x: " << VertexCoordinates.x << ",y: " << VertexCoordinates.y << ",z: "<< VertexCoordinates.z << endl;
}

void addTextureCoordinates(string textureCoordinates)
{
	string textureCoordinateX = pop_number(textureCoordinates);	
	string textureCoordinateY = pop_number(textureCoordinates);
	Vector2d TextureCoordinates;
	TextureCoordinates.x = atof(textureCoordinateX.c_str());
	TextureCoordinates.y = atof(textureCoordinateY.c_str());
	Model.addTextureCoordinates(TextureCoordinates);
}

void addNormals(string Normals)
{
	string NormalX = pop_number(Normals);
	string NormalY = pop_number(Normals);
	string NormalZ = pop_number(Normals);
	Vector3d Normal;
	Normal.x = atof(NormalX.c_str());
	Normal.y = atof(NormalY.c_str());
	Normal.z = atof(NormalZ.c_str());
	Model.addNormal(Normal);
}

void read(){

//mapped_region reg = *getMapping("test.obj");
//void* addr = reg.get_address();
//size_t size = ref.get_size();
string line;
typedef stream<file_source> boostIfstream;

boostIfstream inFile("test.obj");
while(getline(inFile,line))
{
	//cout << line << endl;
	string::size_type pos = line.find_first_not_of(" ");
	if(pos == string::npos) continue;
	line = line.substr(pos);
	if(line.at(0) == '#') continue;
	
	

	pos = line.find("usemtl");
	if(pos != string::npos)
	{
		continue;
	}

	pos = line.find("g");
	if(pos != string::npos)
	{
		continue;
	}


	pos = line.find("vn");
	if(pos != string::npos)
	{
		addNormals(line.substr(pos));
		continue;
	}
	pos = line.find("vt");
	if(pos != string::npos)
	{
		 addTextureCoordinates(line.substr(pos));
		 continue;
	}	

	pos = line.find("v");
	if(pos != string::npos)
	{	
		addVertexCoordinates(line.substr(pos));
		continue;
	}
	pos = line.find("f");
	if(pos != string::npos)
	{
		addPolygon(line.substr(pos));
		continue;
	}	
	
}
}


/**
*@brief the executeable just tests the functionality of readObj
* 
*/
/*int main(){
	read();
	Model.printStatistic();
	return 0;
	
}
*/

Polygons* readObj()
{
	read();
	return &Model;
}

#if 0
mapped_region* getMapping(string filename)
{
	
try{
	//Create a file mapping.
	file_mapping m_file(filename.c_str(), read_write);

	//Map the whole file in this process
	mapped_region region
         (m_file                    //What to map
         ,read_write //Map it as read-write
         );
 
	
	
}
catch(interprocess_exception &ex){
	remove(filename.c_str());
	return NULL;
	
}

	return &region;

}

#endif


